﻿//----------------------------------------------------------------
// Desc: 内存文件,硬盘文件加载器
// Edit: ShowLong, http://blog.csdn.net/showlong
//
// Date Created: 2010-06-11
//
// Update Date :
//
// Copyright (c) Fuel4D (http://www.fuel4d.com), All rights reserved.
//
// 注意：暂不支持对大于2G的文件进行读写操作
//----------------------------------------------------------------
#pragma once


class FMemFile
{
    FDECLARE_CLASS(FMemFile)
public:
    // 默认空构造
    explicit FMemFile()
        :pMemBuffer(0)
        ,nMemLength(0)
        ,nPosition(0)
        ,nFileSize(0)
        ,bCheckFileSize(false)
        ,bAutoDelete(true)
    {}
    // 初始指定大小的内存
    explicit FMemFile(size_t init_size, bool auto_delete = true)
        :nPosition(0)
        ,nFileSize(0)
        ,bCheckFileSize(false)
        ,bAutoDelete(auto_delete)
    {
        pMemBuffer = (init_size > 0 ? FAlloc(BYTE, init_size) : 0);
        nMemLength = pMemBuffer ? init_size : 0;
    }
    // 以其它内存地址来初始化本类
    explicit FMemFile(const BYTE* _data, size_t length, bool auto_delete = true)
        :pMemBuffer((BYTE*)_data)
        ,nMemLength(length)
        ,nPosition(0)
        ,nFileSize(0)
        ,bCheckFileSize(false)
        ,bAutoDelete(auto_delete)
    {}
    // 以文件初始化本类，自动加载该文件
    explicit FMemFile(const WCHAR* filename, const WCHAR* mode, bool auto_delete = true)
        :pMemBuffer(0)
        ,nMemLength(0)
        ,nPosition(0)
        ,bAutoDelete(auto_delete)
    {
        LoadFileW(filename, mode);
    }
    explicit FMemFile(const ACHAR* filename, const ACHAR* mode, bool auto_delete = true)
        :pMemBuffer(0)
        ,nMemLength(0)
        ,nPosition(0)
        ,bAutoDelete(auto_delete)
    {
        LoadFileA(filename, mode);
    }
    virtual~FMemFile()
    {
        if (bAutoDelete)
            Release();
    }
	// 释放由本类创建的内存
	static FINLINE void Free(BYTE*& p)
	{
		FFree(p);
		p = 0;
	}
    // 获取位置
    FINLINE size_t Size() { return nPosition; }
    FINLINE size_t Size() const { return nPosition; }
    // 获取容量
    FINLINE size_t Capacity() { return nMemLength; }
    FINLINE size_t Capacity() const { return nMemLength; }
    // 取首地址
    FINLINE BYTE* Get() { return pMemBuffer; }
    FINLINE BYTE* Get() const { return pMemBuffer; }
    // 定位
    FINLINE void Seek(size_t pos) { nPosition = pos; }
    // 当前内存是否为空
    FINLINE bool IsLoad() { return pMemBuffer != 0; }
    FINLINE bool IsLoad() const { return pMemBuffer != 0; }
    // 手动填充新数据
    FINLINE void Fill(BYTE* _data, size_t length, bool auto_delete)
    {
        Release();

        pMemBuffer = _data;
        nMemLength = length;
        nPosition = 0;
        bAutoDelete = auto_delete;
    }
    // 释放数据
    FINLINE void Release()
    {
        nPosition = nMemLength = nFileSize = 0;
        bCheckFileSize = false;
        if (bAutoDelete && pMemBuffer)
            Free(pMemBuffer);
        pMemBuffer = 0;
    }
    // 仅仅是清理内存标记，不释放
    void Clear()
    {
        nPosition = 0;
    }
    // 重新分配
    FINLINE void ReAllocate(size_t newsize)
    {
        if (newsize < nMemLength)
            return;
        BYTE* pNewBuffer = FAlloc(BYTE, newsize);
        if (!pNewBuffer)
            pNewBuffer = FAlloc(BYTE, newsize);
        if (!pNewBuffer)
            return;
        if (pMemBuffer)
        {
            FMemcpy(pNewBuffer, pMemBuffer, nMemLength);
            if (bAutoDelete)
                Free(pMemBuffer);
            bAutoDelete = true;
        }
        pMemBuffer = pNewBuffer;
        nMemLength = newsize;
    }
    // 写入数据
    FINLINE void* WriteByte(const void* _str, size_t _size, size_t _count)
    {
        if (!_str)
            return 0;
        size_t _data_count = _size * _count;
        if (_data_count <= 0)
            return 0;
        if (!pMemBuffer)
        {
            ReAllocate(_data_count + (_data_count>>1));
            if (!pMemBuffer)
                return 0;
            bAutoDelete = true;
        }
        if (nPosition + _data_count > nMemLength)
            ReAllocate(nMemLength + _data_count + (nMemLength>>1));
        BYTE* dst_pos = pMemBuffer + nPosition;
        FMemcpy(dst_pos, _str, _data_count);
        nPosition += _data_count;
        return dst_pos;
    }
    // 读取数据
    FINLINE void* ReadByte(void* _str, size_t _size, size_t _count)
    {
        if (!_str)
            return 0;
        size_t _data_count = _size * _count;
        if (_data_count <= 0)
            return 0;
        if (!pMemBuffer)
            return 0;
        if (nPosition + _data_count > nMemLength)
            return 0;
        if (bCheckFileSize && nPosition + _data_count > nFileSize)
            return 0;
        FMemcpy(_str, pMemBuffer + nPosition, _data_count);
        nPosition += _data_count;
        if (nPosition > nMemLength)
            nPosition = nMemLength;
        return _str;
    }
    // 保存文件
    FINLINE bool SaveFile(const NCHAR* filename, const NCHAR* mode = _FT("wb+"))
    {
#ifdef UNICODE
        return SaveFileW(filename, mode);
#else
        return SaveFileA(filename, mode);
#endif
    }
    FINLINE bool SaveFileW(const WCHAR* filename, const WCHAR* mode = _FTW("wb+"))
    {
        return SaveFileA(FStringA(filename), FStringA(mode));
    }
    FINLINE bool SaveFileA(const ACHAR* filename, const ACHAR* mode = _FTA("wb+"))
    {
        if (!pMemBuffer)
            return false;
        FMakeDirectoryA(filename);
        FILE* pFile = FOpenA(filename, mode);
        if (!pFile)
            return false;
        // 允许保存0字节的空文件
        FWrite(pMemBuffer, nPosition, 1, pFile);
        FClose(pFile);
        return true;
    }
    // 加载文件
    FINLINE bool LoadFile(const NCHAR* filename, const NCHAR* mode = _FT("rb"))
    {
#ifdef UNICODE
        return LoadFileW(filename, mode);
#else
        return LoadFileA(filename, mode);
#endif
    }
    FINLINE bool LoadFileW(const WCHAR* filename, const WCHAR* mode = _FTW("rb"))
    {
        return LoadFileA(FStringA(filename), FStringA(mode));
    }
    FINLINE bool LoadFileA(const ACHAR* filename, const ACHAR* mode = _FTA("rb"))
    {
        Release();
#if 1
        FV_BYTE buf;
        if (!FFileReadA(filename, &buf))
            return false;
        INT64 file_size = buf.size();
#else
        //FILE* pFile = FOpenA(filename, mode);
        //if (!pFile)
        //    return false;
        //INT64 file_size = FFileSizeA(filename);
#endif
        if (file_size > 0)
        {
            nFileSize = (size_t)file_size;
            bCheckFileSize = true;
            ReAllocate(nFileSize);
#if 1
            FMemcpy(pMemBuffer, buf.get(), nMemLength);
        }
#else
        //    FRead(pMemBuffer, nMemLength, 1, pFile);
        //}
        //FClose(pFile);
#endif
        nPosition = 0;
        return nFileSize > 0 && nMemLength > 0;
    }
    // 加载文件模式时的文件长度
    FINLINE size_t FileSize(){ return nFileSize; }
    // 写指定类型数据
    template < typename _Ty >
    FINLINE _Ty* Write(_Ty* data, size_t count = 1) { return (_Ty*)WriteByte(data, sizeof(_Ty), count); }
    // 读指定类型数据
    template < typename _Ty >
    FINLINE _Ty* Read(_Ty* data, size_t count = 1) { return (_Ty*)ReadByte(data, sizeof(_Ty), count); }
    // 写字符串
    FINLINE NCHAR* WriteStr(FString& str)
    {
#ifdef UNICODE
        return WriteStrW(str);
#else
        return WriteStrA(str);
#endif
    }
    FINLINE WCHAR* WriteStrW(FStringW& str)
    {
        WORD size = (WORD)(sizeof(WCHAR) * str.size());
        if (!Write(&size))
            return 0;
        return (WCHAR*)WriteByte(str.c_str(), size, 1);
    }
    FINLINE ACHAR* WriteStrA(FStringA& str)
    {
        WORD size = (WORD)(sizeof(ACHAR) * str.size());
        if (!Write(&size))
            return 0;
        return (ACHAR*)WriteByte(str.c_str(), size, 1);
    }
    // 读字符串
    FINLINE const NCHAR* ReadStr(FString& str)
    {
#ifdef UNICODE
        return ReadStrW(str);
#else
        return ReadStrA(str);
#endif
    }
    FINLINE const WCHAR* ReadStrW(FStringW& str)
    {
        str.clear();
        WORD size;
        if (!Read(&size))
            return 0;
        if (bCheckFileSize)
        {
            if (nPosition + size > nFileSize)
                return 0;
        }
        else
        {
            if (nPosition + size > nMemLength)
                return 0;
        }
        str.Append((WCHAR*)(pMemBuffer + nPosition), size / sizeof(WCHAR));
        nPosition += size;
        return str.GetString();
    }
    FINLINE const ACHAR* ReadStrA(FStringA& str)
    {
        str.clear();
        WORD size;
        if (!Read(&size))
            return 0;
        if (bCheckFileSize)
        {
            if (nPosition + size > nFileSize)
                return 0;
        }
        else
        {
            if (nPosition + size > nMemLength)
                return 0;
        }
        str.Append((ACHAR*)(pMemBuffer + nPosition), size / sizeof(ACHAR));
        nPosition += size;
        return str.GetString();
    }

protected:
    BYTE* pMemBuffer;       // 当前缓冲区地址
    size_t nMemLength;      // 当前缓冲区内存长度
    size_t nPosition;       // 当前操作游标
    size_t nFileSize;       // 加载文件的时候文件长度
    bool bCheckFileSize;    // 在读取数据时需要检查文件长度
    bool bAutoDelete;       // 是否需要释放内存数据
};